package system.train; 

import java.util.LinkedList;
import system.track.Block;
import system.track.Switch;
import system.track.Direction;
import system.track.SwitchAngle;
import system.track.Sensor;
import system.track.IllegalFunctionCallException;

/**
 * This is an enumeration of actions a train takes
 * every time it tripped a sensor.
 * 
 * @author Yasmine K 
 */
public enum RouteActions 
{
    /**
     * Sets the next switch to 180 degrees.
     */
   SET_NEXT_SWITCH_180 
   {
       boolean executeAction(Train train)
       {
           Direction currentDirection = train.getDirection();
           train.getCurrentBlock().getSwitch(currentDirection).setAngle(SwitchAngle.ONE_EIGHTY_DEGREES);
           return false;
       }
   },

   /**
    * Sets the next switch to 90 degrees.
    */
   SET_NEXT_SWITCH_90
   {
       boolean executeAction(Train train)
       {
           Direction currentDirection = train.getDirection();
           train.getCurrentBlock().getSwitch(currentDirection).setAngle(SwitchAngle.NINETY_DEGREES);
           return false;
       }
   },

   /**
    * Activates the next block by setting its speed and direction to the trains
    * current speed and direction.
    */
   ACTIVATE_NEXT_BLOCK 
   {
       boolean executeAction(Train train)
       {
           Direction currentDirection = train.getDirection();
           Block nextBlock = train.getCurrentBlock().getNextBlock(currentDirection);
           nextBlock.setDirection(currentDirection, train.getSpeed());
           System.out.println("currentBlock ID: " + train.getCurrentBlock().getID()
                   + " nextBlock ID: " + nextBlock.getID());
           return false;
       }
   },

   /**
    * Deactivates the previous block.
    */
   DEACTIVATE_PREVIOUS_BLOCK 
   {
       boolean executeAction(Train train)
       {
           train.getCurrentBlock().setDirection(Direction.CLOCKWISE, 0);
           return false;
       }
   },

   /**
    * Moves the block to the next block in the current direction.
    */
   MOVE_TRAIN_AHEAD
   {
        boolean executeAction(Train train)
        {
            Direction currentDirection = train.getDirection();
            Block nextBlock = train.getCurrentBlock().getNextBlock(currentDirection);
            System.out.println("Moving train to block: " + nextBlock.getID());
            train.setCurrentBlock(nextBlock);
            return false;
        }
   },

   /**
    * Activates the current block of the train.
    */
   ACTIVATE_CURRENT_BLOCK
   {
       boolean executeAction(Train train)
       {
           Direction currentDirection = train.getDirection();
           train.getCurrentBlock().setDirection(currentDirection, train.getSpeed());
           return false;
       }
   },

   /**
    * Sets a block to park.
    */
   SET_BLOCK_TO_PARK 
   {
       boolean executeAction(Train train)
       {
           try
           {
               train.getCurrentBlock().setPark(true);
           }
           catch(IllegalFunctionCallException e) 
           {
           }
           return false;
       }
   },

   /**
    * Sets a block to not park.
    */
   SET_BLOCK_NOT_TO_PARK 
   {
       boolean executeAction(Train train)
       {
           try
           {
               train.getCurrentBlock().setPark(false);
           }
           catch(IllegalFunctionCallException e) 
           {
           }
           return false;
       }
   },

   /**
    * Registers sensors for notification on the next block in the current direction
    * of the train.
    */
   REGISTER_SENSORS 
   {
       boolean executeAction(Train train)
       {
           Direction currentDirection = train.getDirection();
           LinkedList<Sensor> sensors = train.getCurrentBlock().getSensors(currentDirection);
           for(Sensor asensor: sensors)
           {
               asensor.registerForNotification(train);
           }
           return false;
       }
   },

   /**
    * Unregisters sensors for notification.
    */
   UNREGISTER_SENSORS 
   {
       boolean executeAction(Train train)
       {
           /*Direction currentDirection = train.getDirection();
           LinkedList<Sensor> sensors = train.getCurrentBlock().getSensors(currentDirection);
           for(Sensor asensor: sensors)
           {
               asensor.unregisterForNotification(train);
           }*/ //Moved into Sensor functionality becuase of synchronization
               //issue with the hand controlled train.

           return false;
       }
   },

   UNREGISTER_NEXT_SENSORS
   {
       boolean executeAction(Train train)
       {
           Direction currentDirection = train.getDirection();
           LinkedList<Sensor> sensors = train.getCurrentBlock().getNextBlock(currentDirection).getSensors(currentDirection);
           for(Sensor asensor: sensors)
           {
               asensor.unregisterForNotification(train);
           }
           return false;
       }
   },

   /**
    * Switches the current direction of the train.
    */
   TOGGLE_DIRECTION
   {
       boolean executeAction(Train train)
       {
           Direction currentDirection = train.getDirection();
           switch(currentDirection)
           {
                case CLOCKWISE:
                    train.setDirection(Direction.COUNTERCLOCKWISE);
                    break;
                case COUNTERCLOCKWISE:
                    train.setDirection(Direction.CLOCKWISE);
                    break;
           }
           return false;
       } 
   },

   /**
    * Returns true to indicate a wait for sensor trip.
    */
   WAIT_FOR_SENSOR 
   {
       boolean executeAction(Train train)
       {
           return true;
       }
   },

   /**
    * Stops the train by settings its current block's speed to 0.
    */
   STOP
   {
        @Override
       boolean executeAction(Train train)
       {
           train.getCurrentBlock().setDirection(Direction.CLOCKWISE,0);
           return false;
       }
   },


   /**
    * Starts the train by setting its current block's speed to the speed of the
    * train.
    */
   START
   {
       boolean executeAction(Train train)
       {
           train.getCurrentBlock().setDirection(
                   train.getDirection(), train.getSpeed());
           return false;
       }
   },

   /**
    * Starts the train up and activates the next block.
    */
   CONTINUE
   {
       boolean executeAction(Train train)
       {
           RouteActions.START.executeAction(train);
           RouteActions.ACTIVATE_NEXT_BLOCK.executeAction(train);
           return false;
       }
   },

   /**
    * Actives a parking block.
    */
   ACTIVATE_PARKING_BLOCK
   {
       boolean executeAction(Train train)
       {
           boolean returnVal = false;
           Direction d = train.getDirection();
           Block nextBlock = train.getCurrentBlock().getNextBlock(d);
           if (nextBlock.getID() == 4)
           {
               switch(d)
               {
                   case CLOCKWISE:
                       nextBlock.setDirection(Direction.COUNTERCLOCKWISE,
                               train.getSpeed());
                       break;
                   case COUNTERCLOCKWISE:
                       nextBlock.setDirection(Direction.CLOCKWISE,
                               train.getSpeed());
                       break;
                   default:
                }
           } else {
               returnVal = RouteActions.ACTIVATE_NEXT_BLOCK.executeAction(train);
           }
           return returnVal;
       }
   };

   /**
    * Executes an enumeration in the RouteActions.
    *
    * @param train The train to execute the enum action on.
    * @return
    */
   abstract boolean executeAction(Train train);
}
